package sysDao

import (
	"context"
	"gitee.com/jokces/kit/enum"
	"gitee.com/jokces/kit/errc"
	sysModel "gitee.com/jokces/kit/global/admin/model"
	"gitee.com/jokces/kit/typ"
	"xorm.io/xorm"
)

func (d *Dao) MenuList(ctx context.Context, req *sysModel.SysMenu) ([]*sysModel.SysMenu, error) {
	arr := make([]*sysModel.SysMenu, 0)
	sess := d.dao.Context(ctx)
	if req.Id > 0 {
		sess.And("id = ?", req.Id)
	}
	if req.ParentId > 0 {
		sess.And("parent_id = ?", req.ParentId)
	}
	if req.GroupId != "" {
		sess.And("group_id = ?", req.GroupId)
	}
	if req.Status > 0 {
		sess.And("`status` = ?", req.Status)
	}
	if req.MenuName != "" {
		sess.And("menu_name like ?", req.MenuName+"%")
	}
	if req.Show > 0 {
		sess.And("`show` = ?", req.Show)
	}
	if len(req.MenuTypeArr) > 0 {
		sess.In("menu_type", req.MenuTypeArr)
	}
	err := sess.OrderBy("parent_id asc,sequence desc").Find(&arr)
	return arr, errc.WithStack(err)
}
func (d *Dao) MenuGetOne(ctx context.Context, req *sysModel.SysMenu) (bool, *sysModel.SysMenu, error) {
	menus, err := d.MenuList(ctx, req)
	if err != nil {
		return false, &sysModel.SysMenu{}, errc.WithStack(err)
	}
	if menus != nil && len(menus) > 0 {
		return true, menus[0], nil
	}
	return false, &sysModel.SysMenu{}, nil
}
func (d *Dao) MenuListByRoleId(ctx context.Context, roleId int64) ([]*sysModel.SysMenu, error) {
	arr := make([]*sysModel.SysMenu, 0)
	sess := d.dao.Context(ctx).
		Table("sys_menu_role").Alias("smr").
		Join("INNER", []string{"sys_menu", "sm"}, "smr.menu_id = sm.id").
		Join("INNER", []string{"sys_role", "sr"}, "sr.id = smr.role_id").
		Where("smr.role_id = ? and sr.is_del = 0 and sr.`status` = ?  and sm.`status` = ?", roleId, enum.ABLE, enum.ABLE)
	err := sess.OrderBy("sm.parent_id asc,sm.sequence desc").Select("sm.*").Find(&arr)
	return arr, errc.WithStack(err)
}
func (d *Dao) MenuBindActionAll(ctx context.Context, menuId int64) ([]*sysModel.SysAction, error) {
	arr := make([]*sysModel.SysAction, 0)
	err := d.dao.Context(ctx).
		Table("sys_menu_action").Alias("sm").
		Join("INNER", []string{"sys_action", "sa"}, "sm.action_id = sa.id").
		Where("sm.menu_id = ?", menuId).Select("sa.*").Find(&arr)
	return arr, errc.WithStack(err)
}
func (d *Dao) MenuBindActions(ctx context.Context, menu *sysModel.SysMenu, apis []*sysModel.SysAction) error {
	if err := d.dao.Transaction(func(sess *xorm.Session) error {
		//先删除，然后再添加
		if _, err := sess.Context(ctx).And("menu_id = ?", menu.Id).Delete(&sysModel.SysMenuAction{}); err != nil {
			return errc.WithStack(err)
		}
		menus := make([]*sysModel.SysMenuAction, 0)
		for _, api := range apis {
			menus = append(menus, &sysModel.SysMenuAction{
				ActionId: api.Id,
				MenuId:   menu.Id,
			})
		}
		//批量增加对应的API功能数据
		if _, err := sess.Context(ctx).InsertMulti(menus); err != nil {
			return errc.WithStack(err)
		}
		return nil
	}); err != nil {
		return err
	}
	return nil
}
func (d *Dao) MenuListByIds(ctx context.Context, ids []int64) ([]*sysModel.SysMenu, error) {
	arr := make([]*sysModel.SysMenu, 0)
	err := d.dao.Context(ctx).In("id", ids).And("`status` = ?", enum.ABLE).Find(&arr)
	return arr, errc.WithStack(err)
}

func (d *Dao) ActionPageList(ctx context.Context, req *sysModel.SysAction, page *typ.PageReq) (int64, []*sysModel.SysAction, error) {
	arr := make([]*sysModel.SysAction, 0)
	sess := d.dao.Context(ctx)
	if req.Id > 0 {
		sess.And("id = ?", req.Id)
	}
	if req.Status > 0 {
		sess.And("`status` = ?", req.Status)
	}
	if req.GroupId != "" {
		sess.And("`group_id` = ?", req.GroupId)
	}
	if req.ApiName != "" {
		sess.And("api_name like ?", "%"+req.ApiName+"%")
	}
	if req.Api != "" {
		sess.And("api = ?", req.Api)
	}
	if page != nil {
		if row, err := sess.Limit(page.LimitStart()).Desc("id").FindAndCount(&arr); err != nil {
			return 0, arr, errc.WithStack(err)
		} else {
			return row, arr, nil
		}
	}

	if err := sess.Desc("id").Find(&arr); err != nil {
		return 0, arr, errc.WithStack(err)
	} else {
		return int64(len(arr)), arr, nil
	}
}
func (d *Dao) ActionListByIds(ctx context.Context, ids []int64) ([]*sysModel.SysAction, error) {
	arr := make([]*sysModel.SysAction, 0)
	err := d.dao.Context(ctx).In("id", ids).And("`status` = ?", enum.ABLE).Find(&arr)
	return arr, errc.WithStack(err)
}
func (d *Dao) ActionGetOne(ctx context.Context, req *sysModel.SysAction) (bool, *sysModel.SysAction, error) {
	rs := &sysModel.SysAction{}
	row, requests, err := d.ActionPageList(ctx, req, nil)
	if err != nil {
		return false, rs, err
	}
	if row > 0 {
		return true, requests[0], nil
	}
	return false, rs, nil
}

func (d *Dao) RolePageList(ctx context.Context, in *sysModel.SysRole, page *typ.PageReq) (int64, []*sysModel.SysRole, error) {
	arr := make([]*sysModel.SysRole, 0)
	sess := d.dao.Context(ctx)
	sess.And("is_del = 0")
	if in.Id > 0 {
		sess.And("id = ?", in.Id)
	}
	if in.Typ > 0 {
		sess.And("typ = ?", in.Typ)
	}
	if in.Status > 0 {
		sess.And("`status` = ?", in.Status)
	}
	if in.RoleName != "" {
		sess.And("role_name = ?", in.RoleName)
	}
	if in.LikeRoleName != "" {
		sess.And("role_name like ?", in.LikeRoleName+"%")
	}
	if page != nil {
		count, err := sess.Limit(page.LimitStart()).FindAndCount(&arr)
		return count, arr, errc.WithStack(err)
	}
	err := sess.Find(&arr)
	return int64(len(arr)), arr, errc.WithStack(err)
}
func (d *Dao) RoleGetOne(ctx context.Context, req *sysModel.SysRole) (bool, *sysModel.SysRole, error) {
	row, role, err := d.RolePageList(ctx, req, nil)
	if err != nil {
		return false, &sysModel.SysRole{}, errc.WithStack(err)
	}
	if role != nil && row > 0 {
		return true, role[0], nil
	}
	return false, &sysModel.SysRole{}, nil
}
func (d *Dao) RoleActionList(ctx context.Context, roleId int64) ([]*sysModel.SysActionBo, error) {
	arr := make([]*sysModel.SysActionBo, 0)
	err := d.dao.Context(ctx).
		Table("sys_menu_role").Alias("smr").
		Join("INNER", []string{"sys_menu_action", "sm"}, "smr.menu_id = sm.menu_id").
		Join("INNER", []string{"sys_role", "sr"}, "sr.id = smr.role_id").
		Join("INNER", []string{"sys_action", "sa"}, "sm.action_id = sa.id").
		Where("smr.role_id = ? and sr.is_del = 0 and sa.`status` = 1", roleId).Select("sa.id,sa.api_name,sa.api,sa.`code`").Find(&arr)
	return arr, errc.WithStack(err)
}

func (d *Dao) RoleActionIdList(ctx context.Context, roleId int64) ([]int64, error) {
	arr := make([]int64, 0)
	err := d.dao.Context(ctx).
		Table("sys_menu_role").Alias("smr").
		Join("INNER", []string{"sys_menu", "sm"}, "smr.menu_id = sm.id").
		Join("INNER", []string{"sys_role", "sr"}, "sr.id = smr.role_id").
		Where("smr.role_id = ? and sr.is_del = 0 ", roleId).Select("sm.id").Find(&arr)
	return arr, errc.WithStack(err)
}

func (d *Dao) RoleBindMenus(ctx context.Context, role *sysModel.SysRole, apis []*sysModel.SysMenu) error {
	if err := d.dao.Transaction(func(sess *xorm.Session) error {
		//先删除，然后再添加
		if _, err := sess.Context(ctx).And("role_id = ?", role.Id).Delete(&sysModel.SysMenuRole{}); err != nil {
			return errc.WithStack(err)
		}
		menus := make([]*sysModel.SysMenuRole, 0)
		for _, api := range apis {
			menus = append(menus, &sysModel.SysMenuRole{
				RoleId: role.Id,
				MenuId: api.Id,
			})
		}
		//批量增加对应的API功能数据
		if _, err := sess.Context(ctx).InsertMulti(menus); err != nil {
			return errc.WithStack(err)
		}
		return nil
	}); err != nil {
		return err
	}
	return nil
}
